package com.mybatis.sqlsession;

import com.mybatis.config.MapperFunctionInfo;
import com.mybatis.config.MyConfiguration;
import com.util.log.Logger;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.Map;

/**
 * 动态代理生成Mapper对象
 * 优点：单一职责，可扩展性更强
 */
public class MyMapperProxy implements InvocationHandler {
    private final static Logger log = Logger.getLogger(MyMapperProxy.class);

    private MyConfiguration myConfiguration;
    private SqlSession mySqlSession;

    public MyMapperProxy(MyConfiguration myConfiguration, SqlSession mySqlSession) {
        this.myConfiguration = myConfiguration;
        this.mySqlSession = mySqlSession;
    }

    /**
     * 通过代理执行对应的方法
     *
     * @param proxyClass 被代理的接口，只能是接口
     * @param method     代理的方法
     * @param args       形参列表
     * @return
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxyClass, Method method, Object[] args) throws Throwable {
        // 取出被代理的接口类型
        log.trace("代理对象" + proxyClass.getClass());
        Type[] genericInterfaces = Class.forName(proxyClass.getClass().getName()).getGenericInterfaces();
        log.trace("被代理的对象类型[接口]" + genericInterfaces[0]);
        log.trace("代理实现的方法" + method.getName());

        Map<String, MapperFunctionInfo> functionInfoMap =
                myConfiguration.generateFunctionInfoMapOfMapper((Class<?>) genericInterfaces[0]);
        if (functionInfoMap != null) {
            MapperFunctionInfo functionInfo = functionInfoMap.get(method.getName()); // 找到对应函数信息
            log.trace("sql类型：" + functionInfo.getSqlType());
            if (functionInfo.getSqlType().equalsIgnoreCase("select")) {
                return mySqlSession.select(functionInfo.getSql(),
                        args,
                        method.getReturnType(),
                        functionInfo.getResultType());
            } else if (functionInfo.getSqlType().equalsIgnoreCase("insert")) {
                if (args.length < 1)
                    throw new RuntimeException("插入的对象不能为null");
                return mySqlSession.insert(args[0]); // args.length > 0
            }

        }
        return null;
    }
}
